#include <stdio.h>
#include "string.h"
#include "usr_data_buf.h"


void hex_printf(char* name,void* output_data,uint32_t byte_num)
{
 uint8_t* p_data=(uint8_t*)output_data;
 rt_kprintf("%s",name);
 for(uint32_t i=0;i<byte_num;i++)
 {
 	rt_kprintf("%02x ",p_data[i]);
 }
 rt_kprintf("\n");
}


//#define USR_DATA_BUF_DEBUG
#ifndef USR_DATA_BUF_DEBUG
#define rt_kprintf(...) 
#endif
typedef struct
{
	uint8_t end_flag;//一包数据的整体是否发送完毕；1，发送完，0剩余一部分待发
	
	uint8_t data_source;//数据来源 
	uint8_t data_des;//数据发送的对象
	
	uint32_t had_read;//一包数据的已经读取到的总长度
	uint32_t total_len;//一包数据的总长度

	
	uint32_t R_addr;//lkk add 2020-06-09 本包数据的起始位置(与实际读比较，可以分析出是否掩盖旧数据)
  uint32_t R_addr_nest;//lkk add 2020-06-09 下包数据的起始位置
  
}USR_BUF_RECORD_STR;


typedef struct
{
	uint8_t* buf;
	uint32_t buf_size;
	uint32_t r_addr;
	uint32_t w_addr;

	rt_sem_t w_sem;//写占用缓存的信号量：//读取只有在一个线程，所以未使用缓存占用

	USR_BUF_RECORD_STR read_record;
}USR_DATA_CTR_STR;

USR_DATA_CTR_STR usr_data_ctr;

//使用宏，便于书写，以及后期优化操作
#define usr_data_buf (usr_data_ctr.buf)
#define usr_Waddr (usr_data_ctr.w_addr)
#define usr_Raddr  (usr_data_ctr.r_addr)
#define usr_buf_size (usr_data_ctr.buf_size)
#define usr_data_start_addr 8 //前四个字节存储写地址，后四个字节存储读地址
#define usr_data_read_record (usr_data_ctr.read_record)
//USR_BUF_RECORD_STR usr_data_read_record;


/*用户数据缓存的初始化*/
void init_usr_data_buf(void)
{
	uint32_t buf_size; 
	uint8_t* p_buf=usr_data_buf; 

	if(p_buf==RT_NULL)
	{
		buf_size=USR_DATA_BUF_MAX_SIZE;
		while(p_buf==RT_NULL)
		{
			p_buf=rt_malloc(buf_size);
			if(p_buf==RT_NULL)
			{
				buf_size=buf_size*3/4;//减少1/4 再次申请
			}
			else
			{
				memset(p_buf,0,buf_size);
				break;
			}
			
			if(buf_size<2000)
			{
			 rt_kprintf("usr_dta_buf too little\n");
			}
		}
		memset(&usr_data_ctr,0,sizeof(USR_DATA_CTR_STR));//控制结构体初始化
		usr_data_buf=p_buf;
		usr_buf_size=buf_size;
		usr_Raddr=usr_data_start_addr;
		usr_Waddr=usr_data_start_addr;
	}

	

	
	rt_kprintf("usr_dta_buf(0x%p) size:%u\n",usr_data_buf,usr_buf_size);

	/*初始化占用的信号量*/
	usr_data_ctr.w_sem=rt_sem_create("usr_buf",1,RT_IPC_FLAG_FIFO);
	
}



void usr_data_sem_take(rt_int32_t timeout) 
{
	if(usr_data_ctr.w_sem)
	{
		rt_sem_take(usr_data_ctr.w_sem, timeout);
	}
}

void usr_data_sem_release(void)
{
	if(usr_data_ctr.w_sem)
	{
		rt_sem_release(usr_data_ctr.w_sem);
	}
}

void chk_rw_addr(uint32_t* w_addr,uint32_t* r_addr)
{
	if(* w_addr>=usr_buf_size)//
	{
		//addr+=usr_data_start_addr;
		* w_addr=* w_addr%usr_buf_size;//
	}
	if(* w_addr<usr_data_start_addr)
	{
		rt_kprintf("chk_rw_addr W_addr(%u)<start_addr\n",* w_addr);
		* w_addr+=usr_data_start_addr;
	}

	if(* r_addr>=usr_buf_size)//
	{
		//addr+=usr_data_start_addr;
		* r_addr=* r_addr%usr_buf_size;//
	}
	if(* r_addr<usr_data_start_addr)
	{
		rt_kprintf("chk_rw_addr R_addr(%u)<start_addr\n",* r_addr);
		* r_addr+=usr_data_start_addr;
	}
	
}

static void update_Waddr(void)
{
	uint8_t tmp[4]={0};
  
  tmp[0]=(usr_Waddr&0xff000000)>>24;
  tmp[1]=(usr_Waddr&0x00ff0000)>>16;
  tmp[2]=(usr_Waddr&0x0000ff00)>>8;
  tmp[3]= usr_Waddr&0x000000ff;
  memcpy(usr_data_buf,tmp,4);
}
static void update_Raddr(void)
{
	uint8_t tmp[4]={0};
  tmp[0]=(usr_Raddr&0xff000000)>>24;
  tmp[1]=(usr_Raddr&0x00ff0000)>>16;
  tmp[2]=(usr_Raddr&0x0000ff00)>>8;
  tmp[3]= usr_Raddr&0x000000ff;
  memcpy(usr_data_buf+4,tmp,4);
}

static uint32_t circle_buf_remain(void)
 {
 	uint32_t tmp=0;
  if(usr_Waddr>=usr_Raddr)
  tmp=(usr_buf_size-usr_data_start_addr)-(usr_Waddr-usr_Raddr);
  else//反转了
  tmp=usr_Raddr-usr_Waddr;

	 tmp=tmp-1;//不减1,会导致 写完之后恰好读写地址相同。使得数据完全丢失
	 return tmp;
 }
 
uint32_t check_data_num(uint32_t r_addr,uint32_t end_addr)//检查缓存内存储的字节数
{
 uint32_t len;
 len=(r_addr>end_addr)?(usr_buf_size-r_addr+(end_addr-usr_data_start_addr)):(end_addr-r_addr);
 return len;
}

static uint32_t increase_circle_rw_addr(uint32_t addr,uint32_t len)	//lkk replace up 2018-11-30
{
	addr+=len;
	if(addr>=usr_buf_size)//允许上层发来超出边界的地址；认为需要循环到首部
	{
		addr+=usr_data_start_addr;
		addr=addr%usr_buf_size;//进行循环
	}
	
	if(addr<usr_data_start_addr)//默认的起始地址是大于usr_data_start_addr(8)
	{
		addr+=usr_data_start_addr;
	}
	return addr;
}

static void write_circle_mem(uint32_t addr,void*data,uint16_t byte_num)
{
	uint16_t len_tmp=0;	
	if(!byte_num)
	return ;
	//hex_printf("write_circle_mem:",data,byte_num);

	//检验写入地址
	if(addr>=usr_buf_size)//
	{
		//addr+=usr_data_start_addr;
		addr=addr%usr_buf_size;//
	}
	if(addr<usr_data_start_addr)
	{
		rt_kprintf("W_addr(%u)<start_addr\n",addr);
		addr+=usr_data_start_addr;
	}

	if(addr+byte_num>=usr_buf_size)//尾部越界		,进行两次写操作
	{
		len_tmp=byte_num;
		byte_num=usr_buf_size-addr;//尾部剩余空间写入
		len_tmp=len_tmp-byte_num;//反转后首部空间写入
		rt_kprintf("Double_W(%u+%u)\n",byte_num,len_tmp);
	}	

	//内部ram的写入;后期可在此添加外部ram的使用
	memcpy((uint8_t*)usr_data_buf+addr,(uint8_t*)data,byte_num);
	if(len_tmp)
	{
		memcpy((uint8_t*)usr_data_buf+usr_data_start_addr,(uint8_t*)data+byte_num,len_tmp);
	}
	
}


static void read_circle_mem(uint32_t addr,void*data,uint16_t byte_num)
{
	uint16_t len_tmp=0;	
	if(!byte_num)
	return ;
	
	

	//检验写入地址
	if(addr>=usr_buf_size)//
	{
		//addr+=usr_data_start_addr;
		addr=addr%usr_buf_size;//
	}
	if(addr<usr_data_start_addr)
	{
		rt_kprintf("R_addr(%u)<start_addr\n",addr);
		addr+=usr_data_start_addr;
	}

	if(addr+byte_num>=usr_buf_size)//尾部越界		,进行两次读取操作
	{
		len_tmp=byte_num;
		byte_num=usr_buf_size-addr;//尾部剩余空间读取
		len_tmp=len_tmp-byte_num;//反转后首部空间读取
		rt_kprintf("Double_R(%u+%u)\n",byte_num,len_tmp);
	}	

	//内部ram的读取
	memcpy((uint8_t*)data,(uint8_t*)usr_data_buf+addr,byte_num);
	if(len_tmp)
	{
		memcpy((uint8_t*)data+byte_num,(uint8_t*)usr_data_buf+usr_data_start_addr,len_tmp);
	}
	
	//hex_printf("read_circle_mem:",data,byte_num+len_tmp);
}


//一帧数据的结构0xA5,soure_1byte,des_1byte,length_3byte,chk_sum_1byte,data_Nbyte
//length_3byte:高字节在前
enum
{
	frame_fix_index=0,
	frame_soure_index,
	frame_des_index,
	frame_len_16_index,
	frame_len_8_index,
	frame_len_0_index,
	frame_chksum_index,
	
	frame_data_start_index,
};//存储的数据帧 格式
#define FRAME_FIX_HEAD 0xa5
#define FRAME_FIX_HEAD_MASK 0xff

#define FRAME_HEAD_LEN frame_data_start_index

__weak  void post_read_usr_buf(void)//通知上层取数据
{
	return;
}


/*
参数：
@usr_data: 需要copy的数据地址
@byte_num: 待存储的字节个数
@end_flag： 0,未完待续，后面还有数据存储；1，存储一包数据结束
@write_right: 0，不在内部获取写入权限获取，需要在外面获取（一大包数据存入时，防止等后续数据时被其他线程插入数据）；1，写入权限在内部获取和释放


@data_source：		数据来源的标记；数据解析放在读出处理时，解析方案和回应方向可参考此数值进行判断
@send_des:			可用于标记数据发送目的地，或处理方案

返回值：0，失败；1，成功

*/
uint8_t write_usr_buf(void* usr_data,uint16_t byte_num,uint8_t end_flag,uint8_t data_source,uint8_t send_des,uint8_t write_right)
{
	static uint32_t one_pkgt_len=0;
	uint32_t tmp;
	uint32_t w_addr_tmp;
//	USR_DATA_CTR_STR*p_ctr=&usr_data_ctr;
	uint8_t head_buf[FRAME_HEAD_LEN];
	
	if(usr_data_buf==NULL)//没有申请到内存
	{
		return 0;
	}
	
	if((byte_num==0)&&(end_flag==0))//本次无数据进行添加，且未完待续，认为无意义的调度
	{
		return 0;
	}
	
	if((one_pkgt_len+byte_num)==0)//不添加空数据帧
	{
		rt_kprintf("refuse add empty frame\n");
		return 0;
	}
 
	/*获取写入权限；和下面的释放要成对执行*/
	if(write_right)
	{
		usr_data_sem_take(RT_WAITING_FOREVER);
	}
	
	
	w_addr_tmp=usr_Waddr;


	//检查缓存剩余空间;存储空间不够，暂且丢弃处理
	tmp=circle_buf_remain();


	while(tmp<one_pkgt_len+byte_num+FRAME_HEAD_LEN)//没有空间写入
		{
		//之后可使用读出早前存储的数据进行丢弃
			rt_kprintf("#lkk need_space:%u; have:%u\r\n",one_pkgt_len+byte_num+FRAME_HEAD_LEN,tmp);
			usr_Waddr=usr_data_start_addr;
			usr_Raddr=usr_data_start_addr;
		}
		
		/*添加数据帧头*/
		if(end_flag)//一包数据全部到来
		{
			tmp=one_pkgt_len+byte_num;
			head_buf[frame_fix_index]=FRAME_FIX_HEAD;
			
			head_buf[frame_soure_index]=data_source;

			head_buf[frame_des_index]=send_des;
			
			head_buf[frame_len_16_index]=(tmp&0xff0000)>>16;
			head_buf[frame_len_8_index]=(tmp&0xff00)>>8;
			head_buf[frame_len_0_index]=tmp&0xff;

			{
				uint8_t chk_sum=0;
				for(uint16_t ii=0;ii<frame_chksum_index;ii++)
				{
					chk_sum+=head_buf[ii];
				}
				head_buf[frame_chksum_index]=chk_sum;
			}
			//rt_kprintf("write_head_addr:%u\n",w_addr_tmp);
			write_circle_mem(w_addr_tmp,head_buf,FRAME_HEAD_LEN);
			
		}
		
		/*添加数据信息*/
		w_addr_tmp=increase_circle_rw_addr(w_addr_tmp,one_pkgt_len+FRAME_HEAD_LEN);//地址指向数据存储位置
		
		//rt_kprintf("write_data_addr(len:%u):%u\n",byte_num,w_addr_tmp);
		write_circle_mem(w_addr_tmp,usr_data,byte_num);
		
		w_addr_tmp=increase_circle_rw_addr(w_addr_tmp,byte_num);//地址指向下一包数据位置
		if(end_flag)//一包数据全部到来，需要更新写地址
		{
			rt_kprintf("update_W_addr(%u):%u\n",one_pkgt_len+byte_num,w_addr_tmp);
			one_pkgt_len=0;
			usr_Waddr=w_addr_tmp;
			update_Waddr();
			
		}
		else
		{
			one_pkgt_len+=byte_num;
		}

//pro_end:

	/*释放写入权限*/
	if(write_right)
	{
		usr_data_sem_release();
	}
	
	if(end_flag)
	{
		//通知发送端取数据
		post_read_usr_buf();//net_data_send(SEND_MSG_USR_BUF_DATA,(void*)0,0);
	}
	return 1;
}




//读取数据
uint16_t read_usr_buf(uint8_t* buf,uint16_t buf_max,uint8_t* data_source,uint8_t* data_des)
	{
		uint32_t R_addr_tmp; 
		uint32_t ram_store_total; 
		uint32_t frame_size=0; 
		uint16_t read_len=0;
		
		char chk_result=0;
		uint8_t buf_tmp[FRAME_HEAD_LEN];
		
	try_read_again:
	
		R_addr_tmp=usr_Raddr;
	
		/*检查是否有数据*/
		if(R_addr_tmp==usr_Waddr)//无数据
		{
			return 0;
		} 
	
	
		rt_kprintf("%s read_addr:%u,write_addr:%u\r\n",__FUNCTION__,usr_Raddr,usr_Waddr);
	
	
		/*一包数据 继续读取*/
		//是否发生了数据覆盖,数据复位等情况,若发生则记录清除。重新读取ram信息
		
		if(usr_data_read_record.R_addr!=R_addr_tmp)
		{
			//rt_kprintf("#read_addr changge!\n");
			memset(&usr_data_read_record,0,sizeof(usr_data_read_record));
		}
	
		if(usr_data_read_record.end_flag==1)//一包数据已经读取完毕
		{
			rt_kprintf("#read update_r_addr(%u->%u) w:%u\n",usr_Raddr,usr_data_read_record.R_addr_nest,usr_Waddr);
			usr_Raddr=usr_data_read_record.R_addr_nest;
			R_addr_tmp=usr_Raddr;
			update_Raddr();
			usr_data_read_record.end_flag=0;
			
			if(R_addr_tmp==usr_Waddr)//无数据
			{
				return 0;
			}
		}


		
		if(usr_data_read_record.total_len>usr_data_read_record.had_read)//上次没读取完毕
		{
			rt_kprintf("#continue_read:%u/%u\n",usr_data_read_record.had_read,usr_data_read_record.total_len);
			read_len=(buf_max>=usr_data_read_record.total_len-usr_data_read_record.had_read)?(usr_data_read_record.total_len-usr_data_read_record.had_read):buf_max;

			if(buf)
			{
				R_addr_tmp=increase_circle_rw_addr(R_addr_tmp,FRAME_HEAD_LEN+usr_data_read_record.had_read);//lkk add 2020-06-11 跳过已读取的部分
				read_circle_mem(R_addr_tmp,buf,read_len);
			}
			
			usr_data_read_record.had_read+=read_len;
			
			if(data_source)
			{
				*data_source=usr_data_read_record.data_source;
			}
			
			if(data_des)
			{
				*data_des=usr_data_read_record.data_des;
			}
			
			if(usr_data_read_record.had_read==usr_data_read_record.total_len)
			{
				rt_kprintf("#ram_one_read_end\n");
				usr_data_read_record.end_flag=1;
			}
			return read_len;
		}
	
	
		
#if 1
		/*检查及纠正地址信息*/
		R_addr_tmp=R_addr_tmp%usr_buf_size;//地址可以越界
		
		if(R_addr_tmp<usr_data_start_addr)//排除前八个字节的循环缓存
		{
			R_addr_tmp+=usr_data_start_addr;
		}
		if(R_addr_tmp==usr_Waddr)//无数据
		{
			return 0;
		} 
#endif
	
		/*数据量过少，不够存储一个字节的，认为出现了错误*/
	
		ram_store_total=check_data_num(R_addr_tmp,usr_Waddr);
		
		if(ram_store_total<=FRAME_HEAD_LEN)
		{
			rt_kprintf("#ram_store_total(%u)<=FRAME_HEAD_LEN(%u)\n",ram_store_total,FRAME_HEAD_LEN);
			usr_Raddr=usr_Waddr;
			update_Raddr();
			return 0;
		}
	
	
		/*检查匹配符*/
		//rt_kprintf("#R_head_addr:%u:\n",R_addr_tmp);
		read_circle_mem(R_addr_tmp,buf_tmp,FRAME_HEAD_LEN);
		if((buf_tmp[frame_fix_index]&FRAME_FIX_HEAD_MASK)!=FRAME_FIX_HEAD)
		{
			chk_result= 1;
			hex_printf("#ERR_HEAD:",buf_tmp,FRAME_HEAD_LEN);
			goto chk_sync;
		}
		/*检查长度及其校验*/
		{
			uint8_t chk_sum=0;
			for(uint8_t ii=0;ii<frame_chksum_index;ii++)
			{
				chk_sum+=buf_tmp[ii];
			}
			
			frame_size=(buf_tmp[frame_len_16_index]<<16)+(buf_tmp[frame_len_8_index]<<8)+buf_tmp[frame_len_0_index];
			
			if((frame_size==0)||(ram_store_total-FRAME_HEAD_LEN<frame_size)||(buf_tmp[frame_chksum_index]!=chk_sum))
			{
				chk_result= 1;
				rt_kprintf("#err:length:%u(%x===%x)\n",frame_size,buf_tmp[frame_chksum_index],chk_sum);
				goto chk_sync;
			}
		}
		
	
		/*帧检查通过，对其信息进行记录和读取*/
			memset(&usr_data_read_record,0,sizeof(USR_BUF_RECORD_STR));
			usr_data_read_record.total_len=frame_size;
			usr_data_read_record.data_des=buf_tmp[frame_des_index];
			usr_data_read_record.data_source=buf_tmp[frame_soure_index];
			usr_data_read_record.R_addr=R_addr_tmp;
			usr_data_read_record.R_addr_nest=increase_circle_rw_addr(R_addr_tmp,FRAME_HEAD_LEN+frame_size);
		
			R_addr_tmp=increase_circle_rw_addr(R_addr_tmp,FRAME_HEAD_LEN);//跳过头部信息域
			read_len=(frame_size>buf_max)?buf_max:frame_size;
			if(buf)
			{
				read_circle_mem(R_addr_tmp,buf,read_len);
			}
			
			usr_data_read_record.had_read=read_len;
			
			if(read_len<frame_size)
			{
				usr_data_read_record.end_flag=0;
			}
			else
			{
				usr_data_read_record.end_flag=1;
			}

			if(data_source)
			{
				*data_source=usr_data_read_record.data_source;
			}
			
			if(data_des)
			{
				*data_des=usr_data_read_record.data_des;
			}
			
			return read_len;
	
		chk_sync:
		
		#if 1
			usr_Raddr=usr_Waddr;
			update_Raddr();
			goto try_read_again;
		#else
			if(check_R_addr(buf, buf_max))
			{
				goto try_read_again;
			}
		end:
	
		return read_len;
		#endif

	
	
	}

	void test_write_usr_buf(uint8_t argc, char **argv)//测试往用户缓存写入数据
	{
	/*
		static uint32_t send_num=0;
		char tmp_buf[20];
		
		snprintf(tmp_buf,20,"test_num:%u",send_num);
		send_num++;
		write_usr_buf(tmp_buf, strlen(tmp_buf), 1, DATA_SOURCE_UNKNOW, 0, 1);
		*/
		if(argv[1])
		{
			uint32_t len=strlen(argv[1]);
			if(len)
			{
				write_usr_buf(argv[1], len, 1, DATA_SOURCE_UNKNOW, 0, 1);
			}
		}
		else
		{
			rt_kprintf("try_add_empty_frame\n");
			write_usr_buf("Ta", 0, 1, DATA_SOURCE_UNKNOW, 0, 1);
		}
		
	}
	
	MSH_CMD_EXPORT(test_write_usr_buf, test_write_usr_buf);

	void test_wr_addr_set(uint8_t argc, char **argv)
	{
		if(usr_buf_size==0)//还没有初始化内存
		{
		 return;
		}
		
		if(argv[1])
		{
			uint32_t w_addr,r_addr;
			rt_kprintf("rw_addr_set(%u):%s",usr_buf_size,argv[0]);
			if(2==sscanf(argv[1], "%u,%u",&w_addr,&r_addr))
			{
				chk_rw_addr(&w_addr,&r_addr);
				rt_kprintf("cfg:w_addr %u; r_addr %u",w_addr,r_addr);
				usr_Raddr=r_addr;
				usr_Waddr=w_addr;
				update_Waddr();
				update_Raddr();
			}
		}
	}
	
	MSH_CMD_EXPORT(test_wr_addr_set, test_wr_addr_set);


